package com.cherkashyn.vitaliy.devices.ethernet.socket3.commands;

import java.io.IOException;
import java.net.Socket;

import com.cherkashyn.vitaliy.devices.ethernet.socket3.exceptions.ModuleExchangeException;
import com.cherkashyn.vitaliy.devices.ethernet.socket3.exceptions.ReadWriteCommandException;
import com.cherkashyn.vitaliy.devices.ethernet.socket3.exceptions.ResponseTokenException;
import com.cherkashyn.vitaliy.devices.ethernet.socket3.exceptions.UnknownCommandException;

public abstract class BaseCommand<T> {
    private final static byte ERROR_FLAG=0x15;
    @SuppressWarnings("unused")
    private final static long DONT_DELAY=-1L;

    /** full command for request to remote module  */
    protected abstract byte[] getRequestBytes();
    
    /**
     * @return - response command, usually - first byte of request  
     */
    protected byte getFirstResponseByte(){
	return getRequestBytes()[0];
    }

    /** main class for Execute command */
    public Byte execute(Socket socket) throws ModuleExchangeException{
	return doRequest(socket)[getLengthOfResponse()-1];
    }
    
    
    /** 
     * @return - count of byte in response for command request 
     */
    protected abstract int getLengthOfResponse();
    
    /**
     * @return - sleep time in milliseconds before try to read response from socket  
     */
    protected long getDelay(){
	return 150L;
    }
    
    
    protected byte[] doRequest(Socket socket) throws ModuleExchangeException{
	byte[] returnValue=null;
	try{
		if(this.getDelay()>0){
		    returnValue=CommandUtils.doRequest(socket, this.getRequestBytes(), this.getDelay());
		}else{
		    returnValue=CommandUtils.doRequest(socket, this.getRequestBytes());
		}
	}catch(IOException ex){
	    throw new ReadWriteCommandException(ex);
	}
	checkForUnknownCommand(returnValue);
	checkCommandForLenght(returnValue);
	return returnValue;
    }
    

    
    private void checkCommandForLenght(byte[] returnValue) throws ModuleExchangeException{
	if(returnValue.length!=this.getLengthOfResponse()){
		throw new ResponseTokenException(returnValue);
	}
    }

    private void checkForUnknownCommand(byte[] response) throws UnknownCommandException{
	if(response.length>0 && response[0]==ERROR_FLAG){
	    throw new UnknownCommandException(); 
	}
    }

    
}
